# Heart-Animation - 心形动画，支持中文字符，彩色输出
# 程序功能： 输出两个人名，且中间夹带爱心字符的心形程序
# 作者： 魏新崇
# 邮箱： 12028045 [at] zju.edu.cn
# 项目主页： https://gitee.com/weixinchong/heart-animation

import random, time, numpy as np

class Heart():
    
    colors_list = {
        'RED': '\033[31m',  #红色
        'BLUE': '\033[34m',  #蓝色
        'FUCHSIA': '\033[35m',  #紫红色
        'GREEN': '\033[32m',  #绿色
        'YELLOW': '\033[33m',  #黄色
        'CYAN': '\033[36m',  #青蓝色
        'WHITE': '\033[37m'  #白色
    }  #终端配色

    c0 = '\033[0m'  #终端默认颜色

    def __init__(self, name1, name2, interval, color1, color2, max_size, min_size):
        '''心形类初始化
        [参数说明]
        1. name1（str）：左边的人名
        2. name2（str）：右边的人名
        3. interval（float）：每行输出的时间间隔，单位为秒
        4. color（list<str>）：人名每个字符对应的颜色
        5. max_size, min_size（int）：心形的最大、最小尺寸'''
        self.name1 = name1
        self.name2 = name2
        self.interval = interval
        self.color1 = color1
        self.color2 = color2
        self.max_size = max_size
        self.min_size = min_size

    def cs(self, s, color):
        '''输出颜色为color的字符s'''
        return '{}{}{}'.format(self.colors_list[color], s, self.c0)
    
    def draw_heart(self, width, height, r_min):
        '''绘制指定高度、宽度的心形
        [参数说明]
        1. width（int）：高度
        2. height（int）：宽度'''
        # 计算每一个字符的半径范围
        N1 = len(self.name1)
        N2 = len(self.name2)
        N1i = np.arange(N1 + 1)
        N2i = np.arange(N2 + 1)
        rk1 = 1 - (1 - r_min) * (N1i / N1)
        rk2 = 1 - (1 - r_min) * (N2i / N2)
        # 开始生成心形
        for i in range(int(height * 2.5)):
            # 生成左半部分心形
            for j in range(int(width * 2)):
                # 把i,j转变成心形方程里的x,y
                y = 1.5 - i / height
                x = j / width - 1
                # 计算出半径
                r = x**2 + (y - (x**2)**(1/3))**2
                # 如果半径超出规定范围，则生成空格
                if r < r_min or r > 1:
                    print('　', end='')
                    continue
                # 如果半径在规定范围内，则生成对应半径范围内的字符
                for k in range(N1):
                    if r <= rk1[k] and r >= rk1[k+1]:
                        print(self.cs(self.name1[k], self.color1[k]), end='')

            # 生成中间部分爱心
            if i >= int(height*1.25-1) and i <= int(height*1.25+1):
                print('　　❤　❤　　', end='')
            else:
                print('　'*7, end='')

            # 生成右半部分心形
            for j in range(int(width * 2)):
                # 把i,j转变成心形方程里的x,y
                y = 1.5 - i / height
                x = j / width - 1
                # 计算出半径
                r = x**2 + (y - (x**2)**(1/3))**2
                # 如果半径超出规定范围，则生成空格
                if r < r_min or r > 1:
                    print('　', end='')
                    continue
                # 如果半径在规定范围内，则生成对应半径范围内的字符
                for k in range(N2):
                    if r <= rk2[k] and r >= rk2[k+1]:
                        print(self.cs(self.name2[k], self.color2[k]), end='')
            
            # 换行
            print()
            # 暂停一定时间间隔
            time.sleep(self.interval)
        print('\n\n')

    def run(self):
        '''开始自动生成动画'''
        while True:
            height = random.randint(self.min_size, self.max_size)
            width = int(height * 1.4)
            r_min = random.randint(0, 50) / 100
            self.draw_heart(width, height, r_min)


if __name__ == '__main__':
    '''主程序'''
    heart = Heart(
        name1 = '张三',  #左侧的人名
        name2 = '李四',  #右侧的人名
        interval = 0.045,  #每行的时间间隔
        color1 = ['BLUE', 'YELLOW'],  #左侧每个字符的颜色（人名有几个字，就得对应几种颜色！）
        color2 = ['RED', 'CYAN'],  #右侧每个字符的颜色
        max_size = 16,  #心形的最大尺寸
        min_size = 9)  #心形的最小尺寸
    heart.run()